<?php

use app\admin\service\IdentityService;
use app\admin\service\UsersCateService;
use think\facade\Log;

if (!function_exists('ceshi')) {
    function ceshi()
    {
        halt('ceshi');
    }
}

if (!function_exists('plugin_action_exists')) {
    /**
     * 检查插件控制器是否存在某操作
     * @param string $name 插件名
     * @param string $controller 控制器
     * @param string $action 动作
     * @return bool
     */
    function plugin_action_exists($name = '', $controller = '', $action = '')
    {
        if (strpos($name, '/')) {
            list($name, $controller, $action) = explode('/', $name);
        }
        return method_exists("plugins\\{$name}\\controller\\{$controller}", $action);
    }
}

if (!function_exists('plugin_model_exists')) {
    /**
     * 检查插件模型是否存在
     * @param string $name 插件名
     * @return bool
     */
    function plugin_model_exists($name = '')
    {
        return class_exists("plugins\\{$name}\\model\\{$name}");
    }
}

if (!function_exists('plugin_validate_exists')) {
    /**
     * 检查插件验证器是否存在
     * @param string $name 插件名
     * @return bool
     */
    function plugin_validate_exists($name = '')
    {
        return class_exists("plugins\\{$name}\\validate\\{$name}");
    }
}

if (!function_exists('get_plugin_model')) {
    /**
     * 获取插件模型实例
     * @param string $name 插件名
     * @return object
     */
    function get_plugin_model($name)
    {
        $class = "plugins\\{$name}\\model\\{$name}";
        return new $class;
    }
}

if (!function_exists('plugin_action')) {
    /**
     * 执行插件动作
     * 也可以用这种方式调用：plugin_action('插件名/控制器/动作', [参数1,参数2...])
     * @param string $name 插件名
     * @param string $controller 控制器
     * @param string $action 动作
     * @param mixed $params 参数
     * @return mixed
     */
    function plugin_action($name = '', $controller = '', $action = '', $params = [])
    {
        if (strpos($name, '/')) {
            $params = is_array($controller) ? $controller : (array)$controller;
            list($name, $controller, $action) = explode('/', $name);
        }
        if (!is_array($params)) {
            $params = (array)$params;
        }
        $class = "addons\\{$name}\\controller\\{$controller}";
        $obj = new $class;
        return call_user_func_array([$obj, $action], $params);
    }
}

/**
 * 指定时间前开始、结束时间
 * @param int $daysAgo
 * @return array
 */
function getStartEndTime($daysAgo = 14)
{
    // 15天前时间戳
    $s = strtotime('-' . $daysAgo . ' day');
    $e = time();
    $startTime = date('Y-m-d', $s);
    $endTime = date('Y-m-d', strtotime('+1 day'));
    $dateArr = [];
    while ($s <= $e) {
        $dateArr[] = date('d', $s);
        $s += 86400;
    }

    return ['startTime' => $startTime, 'endTime' => $endTime, 'dateArr' => $dateArr];
}

/**
 * 15天内-折线图
 * @param $data
 * @param $labels
 * @return mixed
 */
function inArr($data, $labels)
{
    $datas = [];
    if ($data) {
        foreach ($data as $k => $v) {
            $data[$k]['j'] = date('d', strtotime($v['create_time']));
        }

        foreach ($data as $row) {
            if (isset($datas[(int)$row['j']])) {
                $datas[$row['j']] += $row['total'];
            } else {
                $datas[$row['j']] = $row['total'];
            }
        }
    }

    // 数组键值反转
    $flip = array_flip($labels);
    foreach ($flip as $kkk => $vvv) {
        $flip[$kkk] = isset($datas[$kkk]) ? $datas[$kkk] : 0;
    }

    // 月中
    $label = 'Month';
    $list['label'] = $label;
    $list['labels'] = join(',', $labels);
    $list['datas'] = join(',', array_values($flip));
    return $list;
}

// 折线图-每月
function monthArr($data)
{
    $labels = [];
    // 每月最后一天
    $endDays = date('d', mktime(0, 0, 0, date('m') + 1, 1) - 1);
    for ($i = 1; $i <= $endDays; $i++) {
        $labels[] = $i;
    }
    $datas = [];
    if ($data) {
        foreach ($data as $k => $v) {
            $data[(int)$k]['j'] = date('d', strtotime($v['create_time']));
        }

        foreach ($data as $row) {
            if (isset($datas[(int)$row['j']])) {
                $datas[(int)$row['j']] += $row['total'];
            } else {
                $datas[(int)$row['j']] = $row['total'];
            }
        }
    }

    foreach ($labels as $k => $v) {
        if (!array_key_exists($v, $datas)) {
            $datas[$v] = 0;
        }
    }
    ksort($datas);

    // 每月
    $label = 'Month';
    $list['label'] = $label;
    $list['labels'] = join(',', $labels);
    $list['datas'] = join(',', array_values($datas));
    return $list;
}

// 折线图-每周
function weekArr($data)
{
    $labels = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
    $datas = [];
    if ($data) {
        foreach ($data as $k => $v) {
            $data[(int)$k]['w'] = date('w', strtotime($v['create_time']));
        }
        foreach ($data as $row) {
            if (isset($datas[(int)$row['w']])) {
                $datas[(int)$row['w']] += $row['total'];
            } else {
                $datas[(int)$row['w']] = $row['total'];
            }
        }
    }

    foreach ($labels as $k => $v) {
        if (!array_key_exists($k, $datas)) {
            $datas[$k] = 0;
        }
    }
    ksort($datas);

    // 每周
    $label = 'Week';
    $list['label'] = $label;
    $list['labels'] = join(',', $labels);
    $list['datas'] = join(',', array_values($datas));
    return $list;
}

// 随机颜色
function random_color($colorsArr = [])
{
    mt_srand((double)microtime() * 1000000);
    $c = '';
    while (strlen($c) < 6) {
        $c .= sprintf("%02X", mt_rand(0, 255));
    }
    if (in_array($c, $colorsArr)) {
        random_color($colorsArr);
    }
    return $c;
}

/**
 * 是否存在协议标识
 * @param $val
 * @return bool
 */
function isHasProtocol($val)
{
    if (preg_match('/(http:\/\/)|(https:\/\/)/i', $val)) {
        return true;
    }
    return false;
}


/**
 * emoji表情转义
 * @param $str
 * @return string
 */
function emojiEncode($str)
{
    $strEncode = '';
    $length = mb_strlen($str, 'utf-8');
    for ($i = 0; $i < $length; $i++) {
        $_tmpStr = mb_substr($str, $i, 1, 'utf-8');
        if (strlen($_tmpStr) >= 4) {
            $strEncode .= '[[EMOJI:' . rawurlencode($_tmpStr) . ']]';
        } else {
            $strEncode .= $_tmpStr;
        }
    }
    return $strEncode;
}

/**
 * emoji表情反转义
 * @param $str
 * @return string|string[]|null
 */
function emojiDecode($str)
{
    $strDecode = preg_replace_callback('|\[\[EMOJI:(.*?)\]\]|', function ($matches) {
        return rawurldecode($matches[1]);
    }, $str);
    return $strDecode;
}

/**
 * 生成会员编号
 * @return string
 */
function generateCode()
{
    $code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $rand = $code[rand(0, 25)]
        . strtoupper(dechex(date('m')))
        . date('d')
        . substr(time(), -5)
        . substr(microtime(), 2, 5)
        . sprintf('%02d', rand(0, 99));
    for (
        $a = md5($rand, true),
        $s = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
        $d = '',
        $f = 0;
        $f < 8;
        $g = ord($a[$f]),
        $d .= $s[($g ^ ord($a[$f + 8])) - $g & 0x1F],
        $f++
    ) ;
    return $d;
}

/**
 * 社群编号
 * @param $uid
 * @return string
 */
function getResourceNumber($uid)
{
    return '0' . $uid . 'H';
}

/**
 * 生成订单号
 * @return string
 */
function generateOrderNo()
{
    $code = date('ymdH') . substr((string)time(), -5) . sprintf('%02d', rand(0, 99) . substr((string)microtime(), 2, 5));
    return $code;
}

/**
 * 角色
 * @param $role
 * @return string
 */
function getRoleName($role)
{
    // 1年会员  2日会员  3月会员  0游客
    switch ($role) {
        case 1:
            $role = '年VIP';
            break;
        case 2:
            $role = '日VIP';
            break;
        case 3:
            $role = '月VIP';
            break;
        default:
            $role = '游客';
    }

    return $role;
}

/**
 * 地区数据
 * @param $data
 * @return array
 */
function getAreaData($data)
{
    $datas = [];
    $colorsArr = ['#F25021', '#F8AC16', '#4F1DF6', '#5B78FF', '#FF6363', '#29abe2'];
    foreach ($data as $k => $v) {
        $name = $v['name'] ?: '其他';
        if (strrpos($v['name'], '市')) {
            $name = substr_replace($v['name'], '', strrpos($v['name'], '市'));
        }
        $datas[] = json_encode([
            'value' => $v['nums'],
            'name' => $name,
            'label' => [
                'color' => $colorsArr[$k],
                'fontWeight' => 'bold',
            ],
        ], JSON_UNESCAPED_UNICODE);
    }

    return join(';', $datas);
}

/**
 * 身份数据
 * @param $peopleList
 * @param int $is_count_values 1默认需查询对应的身份  0无需查询
 * @param int $is_marketing 0默认为其他  1营销活动数据
 * @return string
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\DbException
 * @throws \think\db\exception\ModelNotFoundException
 */
function getIdentityData($peopleList, $is_count_values = 1, $is_marketing = 0)
{
    // 获取对应的身份名称
    if ($is_count_values) {
        $identityData = [];
        foreach ($peopleList as $people) {
            $identity = UsersCateService::findUsersIdentity(['uid' => $people['uid']]);
            $identity = $identity ?: '游客';
            $identityData[] = $identity;
        }
        // 统计相同键的数据，组成新数组
        $valueArr = array_count_values($identityData);
    } else {
        $valueArr = $peopleList;
    }

    // 获取原身份数据
    $identityList = IdentityService::getIdentityList();
    $newArr = [];
    foreach ($identityList as $k => $v) {
        $newArr[$v['name']] = isset($valueArr[$v['name']]) ? $valueArr[$v['name']] : 0;
    }

    $nameArr = [];
    $valueArr = [];
    // 拼接返回
    if (!$is_marketing) {
        foreach ($newArr as $name => $value) {
            $nameArr[] = "{a|" . $name . "}
{c|" . $value . "}";
            $valueArr[] = $value;
        }
    } else {
        $colors = ['#FF6363FF', '#E6A500FF', '#8FDFFEFF', '#3793FAFF', '#233AE2FF', '#5B78FFFF', '#915BFFFF', '#FA32A3FF'];
        $colorsKey = 0;
        $valueNums = 0;
        foreach ($newArr as $name => $value) {
            $itemStyle['normal'] = ['color' => $colors[$colorsKey]];
            $nameArr[] = json_encode(['value' => $value,
                'name' => "{a|" . $name . "}
{c|" . $value . "}",
                'itemStyle' => $itemStyle
            ], JSON_UNESCAPED_UNICODE);
            $colorsKey++;
            $valueNums += $value;
        }

        return ['nameArr' => join(';', $nameArr), 'valueNums' => $valueNums];
    }

    return join(';', $nameArr) . '&&' . join(';', $valueArr);
}

/**
 * * 附件上传
 * 上传文件函数，如过上传不成功打印$_FILES数组，查看error报错信息
 * 值：0; 没有错误发生，文件上传成功。
 * 值：1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
 * 值：2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
 * 值：3; 文件只有部分被上传。
 * 值：4; 没有文件被上传。
 * @param int $is_return
 * @return \think\response\Json
 */
function annexReturn($is_return = 0)
{
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Content-type: text/html; charset=gbk32");
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");
    $folder = input('folder');
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        exit; // finish preflight CORS requests here
    }
    if (!empty($_REQUEST['debug'])) {
        $random = rand(0, intval($_REQUEST['debug']));
        if ($random === 0) {
            header("HTTP/1.0 500 Internal Server Error");
            exit;
        }
    }
    // header("HTTP/1.0 500 Internal Server Error");
    // exit;
    // 5 minutes execution time
    set_time_limit(5 * 60);
    // Uncomment this one to fake upload time
    usleep(5000);

    $topDir = '/public' . DIRECTORY_SEPARATOR;
    // 存放分片临时目录
    $targetDir = $_SERVER['DOCUMENT_ROOT'] . $topDir . 'file_annex_tmp';


    // 分片合并存放目录
    if ($folder) {

        $subDir = $topDir . 'file_annex' . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR . date('Ymd');

        $uploadDir = $_SERVER['DOCUMENT_ROOT'] . $subDir;

    } else {
        $subDir = $topDir . 'file_annex' . DIRECTORY_SEPARATOR . date('Ymd');

        $uploadDir = $_SERVER['DOCUMENT_ROOT'] . $subDir;

    }

    $cleanupTargetDir = true; // Remove old files
    $maxFileAge = 5 * 3600; // Temp file age in seconds

    // Create target dir
    if (!file_exists($targetDir)) {
        mkdir($targetDir, 0777, true);
    }
    // Create target dir
    if (!file_exists($uploadDir)) {
        mkdir($uploadDir, 0777, true);
    }
    // Get a file name
    if (isset($_REQUEST["name"])) {
        $fileName = $_REQUEST["name"];
    } elseif (!empty($_FILES)) {
        $fileName = $_FILES["file"]["name"];
    } else {
        $fileName = uniqid("file_");
    }
    $oldName = $fileName;

    $fileName = iconv('UTF-8', 'GBK', $fileName);
    $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
    // $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
    // Chunking might be enabled
    $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
    $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
    // Remove old temp files
    if ($cleanupTargetDir) {
        if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory111."}, "id" : "id"}');
        }
        while (($file = readdir($dir)) !== false) {
            $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
            // If temp file is current file proceed to the next
            if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
                continue;
            }
            // Remove temp file if it is older than the max age and is not the current file
            if (preg_match('/\.(part|parttmp)$/', $file)) {
                Log::write('file:' . json_encode($file), 'error');
                if (file_exists($tmpfilePath)) {
                    Log::write('file_exists:' . json_encode($tmpfilePath), 'error');
                    // 文件上次的修改时间
                    if (@filemtime($tmpfilePath) < time() - $maxFileAge) {
                        @unlink($tmpfilePath);
                    }
                }
            }
        }
        closedir($dir);
    }
    // Open temp file
    if (!$out = fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
        die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream222."}, "id" : "id"}');
    }
    if (!empty($_FILES)) {
        if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file333."}, "id" : "id"}');
        }
        // Read binary input stream and append it to temp file
        if (!$in = fopen($_FILES["file"]["tmp_name"], "rb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream444."}, "id" : "id"}');
        }
    } else {
        if (!$in = fopen("php://input", "rb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream555."}, "id" : "id"}');
        }
    }
    while ($buff = fread($in, 4096)) {
        fwrite($out, $buff);
    }
    fclose($out);
    fclose($in);
    rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
    $index = 0;
    $done = true;
    for ($index = 0; $index < $chunks; $index++) {
        if (!file_exists("{$filePath}_{$index}.part")) {
            $done = false;
            break;
        }
    }

    if ($done) {
        $pathInfo = pathinfo($fileName);
        $hashStr = substr(md5($pathInfo['basename']), 8, 16);
        $hashName = time() . $hashStr . '.' . $pathInfo['extension'];
        $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $hashName;
        $uploadPath1 = DIRECTORY_SEPARATOR . $hashName;
        if (!$out = fopen($uploadPath, "wb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream666."}, "id" : "id"}');
        }
        //flock($hander,LOCK_EX)文件锁
        if (flock($out, LOCK_EX)) {
            for ($index = 0; $index < $chunks; $index++) {
                if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
                    break;
                }
                while ($buff = fread($in, 4096)) {
                    fwrite($out, $buff);
                }
                fclose($in);
                unlink("{$filePath}_{$index}.part");
            }
            flock($out, LOCK_UN);
        }
        fclose($out);

        $response = [
            'success' => true,
            'oldName' => $oldName,
            // 把反斜杠(\)替换成斜杠(/) 因为在windows下上传路径是反斜杠径
            'filePath' => str_replace("\\", "/", $uploadPath),
            'subFilePath' => str_replace("\\", "/", $subDir . $uploadPath1),
//                'fileSize'=>$data['size'],
            'fileSuffixes' => $pathInfo['extension'],          //文件后缀名
//                'file_id'=>$data['id'],
        ];

        $r = Cache::set($response['subFilePath'], $response['oldName']);
        Log::write('cacheKey：' . $response['subFilePath'], 'error');
        Log::write('cacheValue：' . $response['oldName'], 'error');
        Log::write('cacheRes：' . $r, 'error');

        return json($response);
    }

    // Return Success JSON-RPC response
    die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
}

/**
 * 社群售卖编号
 * @param $number
 * @param $lastId
 * @return string
 */
function getResourceSaleNumber($number, $lastId)
{
    switch ($number) {
        case $number >= 0 && $number <= 49:
            $level = 'S';
            break;
        case $number >= 50 && $number <= 99:
            $level = 'A';
            break;
        case $number >= 100 && $number <= 299:
            $level = 'B';
            break;
        case $number >= 300 && $number <= 499:
            $level = 'C';
            break;
        default:
            $level = 'D';
            break;
    }

    if (!$lastId) {
        return $level;
    }

    // 最大长度
    $maxLen = 5;
    // 实际长度
    $strLen = strlen((string)$lastId);
    // 剩余长度
    $len = $maxLen - $strLen;

    $str_pad = str_pad((string)$lastId, $strLen + $len, '0', STR_PAD_LEFT);

//    return $level . date('YmdHis', time()) . $str_pad;
    return $level . $str_pad;
}

// 后台数据返回
function adminResponseJson($data = [], $code = 0)
{
    return json([
        'code' => $code,
        'msg' => '数据列表',
        'data' => $data,
    ]);
}

/**
 * curl请求
 * @param $url
 * @param int $post
 * @param array $data
 * @return mixed
 */
function httpRequest($url, $post = 0, $data = array())
{
    //初使化init方法
    $ch = curl_init();
    if (!$post) {
        $url = $data ? $url . '?' . http_build_query($data) : $url;
    }
    //指定URL
    curl_setopt($ch, CURLOPT_URL, $url);
    //设定请求后返回结果
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if ($post == 1) {
        curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false);
        //声明使用POST方式来进行发送
        curl_setopt($ch, CURLOPT_POST, 1);
        //发送数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
    }
    //忽略证书
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    //忽略header头信息
    curl_setopt($ch, CURLOPT_HEADER, 0);
    //设置超时时间
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    //发送请求
    $output = curl_exec($ch);
    Log::write( 'curl请求，发送请求' . json_encode($output), 'error');

    // 返回一个保护当前会话最近一次错误的字符串
    $error = curl_error($ch);
    Log::write( 'curl请求，错误的字符串' . json_encode($error), 'error');

    // 返回最后一次的错误号
    $errno = curl_errno($ch);
    Log::write( 'curl请求，错误号' . json_encode($errno), 'error');

    //关闭curl
    curl_close($ch);
    //返回数据
    return json_decode($output, true);
}

/**
 * 涨知识分类
 * @param $source
 * @return string
 */
function getArticleCateName($source)
{
    switch ($source) {
        case 2:
            $sourceName = '社群知识';
            break;
        case 3:
            $sourceName = '社群案例';
            break;
        default:
            $sourceName = '企业微信';
    }

    return $sourceName;
}

/**
 * 后台json信息返回
 * @param $code
 * @return mixed
 */
function adminJsonMsg($code)
{
    $msgArr = [
        1001 => '参数错误',
        1002 => '数据不存在',
        1003 => '操作失败',
        1004 => '操作成功',
        1005 => '该数据已被推荐',
        1006 => '别闹，请认真输入用户ID',
        1007 => '请先取消该数据的推荐，再进行操作',
        1008 => '该社群编号已被使用，修改后提交',
        1009 => '上门时间不允许小于当前时间',
        10010 => '用户ID输入无效，请核对后输入',
        10011 => '别闹，请认真输入登记人ID',
        10012 => '登记人ID输入无效，请核对后输入',
        10013 => '该反馈已回复，无需重复',
        10014 => '社群数据不存在',
        10015 => '该标题已存在，修改后添加',
        10016 => '该分类已在文章中使用，请先删除对应的文章数据',
        10017 => '二维码生成失败',
        10018 => 'token获取失败',
        10019 => '请填写备注信息',
        10020 => '经办人不存在，请修改添加',
        10021 => '该社群名称已存在，请修改提交',
        10022 => '该提现申请被驳回或打款，请联系管理员',
        10023 => '当前用户未关注公众号，请先引导关注',
        10024 => '打款失败，请稍后再试',
        10025 => '职位薪资范围选择有误',
        10026 => '该企业社群已存在，请修改后提交',
        10027 => '所选企业数据不存在，请重新选择后提交',
        10028 => '该企业已被认证，请修改后提交',
        10029 => '请选择所属行业或自定义填写一个行业',
        10030 => '您自定义的行业存在一级分类中，请修改后提交',
    ];

    return $msgArr[$code];
}